package ar.republicagroup.gestion.services.impl;

import ar.republicagroup.gestion.config.RGroupAppConfig;
import ar.republicagroup.gestion.dao.CalendarioBancarioDAO;
import ar.republicagroup.gestion.entities.CalendarioBancario;
import ar.republicagroup.gestion.services.CalendarioBancarioServices;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import net.objectlab.kit.datecalc.common.DateCalculator;
import net.objectlab.kit.datecalc.common.DefaultHolidayCalendar;
import net.objectlab.kit.datecalc.common.HolidayCalendar;
import net.objectlab.kit.datecalc.common.HolidayHandlerType;
import net.objectlab.kit.datecalc.jdk.CalendarKitCalculatorsFactory;
import org.apache.log4j.Logger;

/**
 *
 * @author DIEGOALV
 */
public class CalendarioBancarioServicesImpl implements CalendarioBancarioServices {

    CalendarioBancarioDAO calendarioBancarioDao;
    Logger log = Logger.getLogger(CalendarioBancarioServicesImpl.class);
   
    
    public void setCalendarioBancarioDao(CalendarioBancarioDAO calendarioBancarioDao) {
        this.calendarioBancarioDao = calendarioBancarioDao;
    }
   
    @Override
    public Set<CalendarioBancario> findEntities() {
        return calendarioBancarioDao.findEntities();
    }

    @Override
    public String insert(CalendarioBancario nuevoFeriado) {
        return calendarioBancarioDao.insert(nuevoFeriado);
    }

    @Override
    public String delete(CalendarioBancario feriado) {
        return calendarioBancarioDao.delete(feriado);
    }

    @Override
    public Calendar calcularFechaDeLiquidacion() {
        
        if(RGroupAppConfig.getProperty("DEBUG_MODE").toString().equals("0")){
            /* Cargamos los feriados y los pasamos a un Set<Calendar>*/
            Set<Calendar> feriados;
            final HolidayCalendar<Calendar> calendarioAnhoActual;

            feriados                = cargarFeriadosDesdeBD();
            calendarioAnhoActual    = crearCalendarioConFeriados(feriados);
            // register the holidays, any calculator with name "AR"
            // asked from now on will receive an IMMUTABLE reference to this calendar
            CalendarKitCalculatorsFactory.getDefaultInstance().registerHolidays("AR", calendarioAnhoActual);
             // ask for a LocalDate calculator for "AR"
            // (even if a new set of holidays is registered, this one calculator is not affected
            DateCalculator<Calendar> cal = CalendarKitCalculatorsFactory.getDefaultInstance()
            .getDateCalculator("AR", HolidayHandlerType.BACKWARD);
           //(even if a new set of holidays is registered, this one calculator is not affected
            Calendar currentDate = Calendar.getInstance();
            // set startDate, this will also set the current business date.
            cal.setStartDate(currentDate);
            Calendar start = cal.getStartDate();   
            Calendar current;
            current = cal.moveByBusinessDays(-2).getCurrentBusinessDate();
            return current;
        } else {
            String fechaDebugLiquid = RGroupAppConfig.getProperty("FECHA_DEBUG_LIQUID");
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    Date dateLiquid = formatter.parse(fechaDebugLiquid);
                    Calendar fechaCalendarDebug = Calendar.getInstance();
                    fechaCalendarDebug.setTime(dateLiquid);
                    log.info("Activado el Debug de Liquidaciones ---> Fecha ingresada : "+fechaCalendarDebug.getTime().toString());
                    return fechaCalendarDebug;
                
                } catch (ParseException ex) {
                   log.error(ex.getMessage(), ex);
                   return null;
                }
                
        }
        
    }


    
    @Override
    public Calendar calcularSiguienteDiaHabil() {
         /* Cargamos los feriados y los pasamos a un Set<Calendar>*/
        Set<Calendar> feriados;
        final HolidayCalendar<Calendar> calendarioAnhoActual;
        feriados                = cargarFeriadosDesdeBD();
        calendarioAnhoActual    = crearCalendarioConFeriados(feriados);
        CalendarKitCalculatorsFactory.getDefaultInstance().registerHolidays("AR2", calendarioAnhoActual);
        DateCalculator<Calendar> cal = CalendarKitCalculatorsFactory.getDefaultInstance()
        .getDateCalculator("AR2", HolidayHandlerType.FORWARD);
       
        Calendar currentDate = Calendar.getInstance();
        cal.setStartDate(currentDate);
        Calendar start = cal.getStartDate();   
        Calendar current;
        current = cal.moveByBusinessDays(1).getCurrentBusinessDate();
        
        return current;
    }
    
 
    private Set<Calendar> cargarFeriadosDesdeBD(){
        Set<CalendarioBancario> feriadosList = calendarioBancarioDao.findEntities();
        Set<Calendar> feriadosSet = new HashSet<>();
        
        for(CalendarioBancario feriado : feriadosList){
            Calendar feriadoCalendar = Calendar.getInstance();
            feriadoCalendar.setTime(feriado.getFechaFeriado());
            feriadosSet.add(feriadoCalendar);
        }
        
        return feriadosSet;
    }
    
    public HolidayCalendar<Calendar> crearCalendarioConFeriados(Set<Calendar> feriados){
        Calendar primerDiaDelAnho = Calendar.getInstance();
        primerDiaDelAnho.set(Calendar.YEAR, 2013);
        primerDiaDelAnho.set(Calendar.MONTH, Calendar.JANUARY);
        primerDiaDelAnho.set(Calendar.DAY_OF_MONTH, 1);
        
        Calendar ultimoDiaDelAnho = Calendar.getInstance();
        ultimoDiaDelAnho.set(Calendar.YEAR, Calendar.getInstance().get(Calendar.YEAR));
        ultimoDiaDelAnho.set(Calendar.MONTH, Calendar.DECEMBER);
        ultimoDiaDelAnho.set(Calendar.DAY_OF_MONTH, 31);

        //Create the HolidayCalendar del anho actual
        final HolidayCalendar<Calendar> calendarioAnhoActual = new DefaultHolidayCalendar<>
                (feriados, primerDiaDelAnho, ultimoDiaDelAnho);
        
        return calendarioAnhoActual;
    }

    @Override
    public Calendar calcularFechaDeProximaLiquidacion() {
        /* Cargamos los feriados y los pasamos a un Set<Calendar>*/
        Set<Calendar> feriados;
        final HolidayCalendar<Calendar> calendarioAnhoActual;
        
        feriados                = cargarFeriadosDesdeBD();
        calendarioAnhoActual    = crearCalendarioConFeriados(feriados);
        // register the holidays, any calculator with name "AR"
        // asked from now on will receive an IMMUTABLE reference to this calendar
        CalendarKitCalculatorsFactory.getDefaultInstance().registerHolidays("AR", calendarioAnhoActual);
         // ask for a LocalDate calculator for "AR"
        // (even if a new set of holidays is registered, this one calculator is not affected
        DateCalculator<Calendar> cal = CalendarKitCalculatorsFactory.getDefaultInstance()
        .getDateCalculator("AR", HolidayHandlerType.BACKWARD);
       //(even if a new set of holidays is registered, this one calculator is not affected
        Calendar currentDate = Calendar.getInstance();
        // set startDate, this will also set the current business date.
        cal.setStartDate(calcularSiguienteDiaHabil());
        Calendar start = cal.getStartDate();   
        Calendar current;
        current = cal.moveByBusinessDays(-2).getCurrentBusinessDate();
        return current;
    }

    @Override
    public Calendar calcularAnteriorDiaHabil(Calendar selectedDate) {
         Set<Calendar> feriados;
        final HolidayCalendar<Calendar> calendarioAnhoActual;
        feriados                = cargarFeriadosDesdeBD();
        calendarioAnhoActual    = crearCalendarioConFeriados(feriados);
        CalendarKitCalculatorsFactory.getDefaultInstance().registerHolidays("AR2", calendarioAnhoActual);
        DateCalculator<Calendar> cal = CalendarKitCalculatorsFactory.getDefaultInstance()
        .getDateCalculator("AR2", HolidayHandlerType.BACKWARD);
       
        cal.setStartDate(selectedDate);
        Calendar start = cal.getStartDate();   
        Calendar current;
        current = cal.moveByBusinessDays(-1).getCurrentBusinessDate();
        
        return current;
    }

    @Override
    public boolean isHoliday(Date date , Set<CalendarioBancario> calendario) {
        
        boolean isHoliday = false;
        
        Calendar myDate = Calendar.getInstance();
        myDate.setTime(date);
        
        Calendar holiday = Calendar.getInstance();
        
        for(CalendarioBancario aDate : calendario){
            holiday.setTime(aDate.getFechaFeriado());
            if(myDate.get(Calendar.YEAR) == holiday.get(Calendar.YEAR) &&
                  myDate.get(Calendar.DAY_OF_YEAR) == holiday.get(Calendar.DAY_OF_YEAR)){
                  isHoliday = true;
                  break;
                }
        }
        
        return isHoliday;      
    }
    
    
    
    
    
}
